package com.mayflygeek.mayflyask.framework.orm;

import java.io.Serializable;
import java.util.List;

import org.springframework.data.domain.Page;

/**
 * @author 虫虫
 * @team 蜉蝣极客
 * @link www.mayflygeek.com
 * @Emial chongchong@mayflygeek.com
 * 
 */
public interface BaseDao<T, ID extends Serializable> {
	/**
	 * 获取实体对象
	 * 
	 * @param id
	 *            ID
	 * @return 返回对应id的实体对象
	 * @throws RuntimeException
	 *             如果未找到对应的id实体
	 */
	T get(ID id);

	/**
	 * 获取实体对象
	 * 
	 * @param id
	 *            ID
	 * @param that
	 *            默认对象
	 * @return 返回对应id的实体对象，如果对象不存在，返回默认对象
	 */
	T getOrElse(ID id, T that);

	/**
	 * 保存实体
	 * 
	 * @param entity
	 *            要保存的实体对象
	 * @return 返回已保存的实体对象
	 */
	T save(T entity);

	/**
	 * 保存实体
	 * 
	 * @param entity
	 *            要保存的实体
	 * @param rest
	 *            其余要保存的实体对象
	 * @return 返回已保存的实体对象列表
	 */
	@SuppressWarnings("unchecked")
	List<T> save(T entity, T... rest);

	/**
	 * 保存实体
	 * 
	 * @param entities
	 *            要保存的实体数组
	 * @return 返回已保存的实体对象列表
	 */
	List<T> save(T[] entities);

	/**
	 * 更新实体
	 * 
	 * @param entity
	 *            要更新的实体对象
	 * @return 返回已更新的实体对象
	 */
	T update(T entity);

	/**
	 * 更新实体
	 * 
	 * @param entity
	 *            要更新的实体对象
	 * @param rest
	 *            其余要更新的实体对象
	 * @return 返回已更新的实体对象列表
	 */
	@SuppressWarnings("unchecked")
	List<T> update(T entity, T... rest);

	/**
	 * 更新实体
	 * 
	 * @param entities
	 *            要更新的实体数组
	 * @return 返回已更新的实体对象列表
	 */
	List<T> update(T[] entities);

	/**
	 * 删除实体
	 * 
	 * @param entity
	 *            要删除的实体对象
	 */
	void delete(T entity);

	/**
	 * 删除实体
	 * 
	 * @param entity
	 *            要删除的实体对象
	 * @param rest
	 *            其余要删除的实体对象
	 */
	@SuppressWarnings("unchecked")
	void delete(T entity, T... rest);

	/**
	 * 删除实体
	 * 
	 * @param entities
	 *            要删除的实体数组
	 */
	void delete(T[] entities);

	/**
	 * 通过id删除实体
	 * 
	 * @param id
	 *            要删除的实体id
	 */
	void deleteById(ID id);

	/**
	 * 通过id删除实体
	 * 
	 * @param id
	 *            要删除的实体id
	 * @param rest
	 *            其余要删除的实体id
	 */
	@SuppressWarnings("unchecked")
	void deleteById(ID id, ID... rest);

	/**
	 * 通过Id删除实体
	 * 
	 * @param ids
	 *            要删除的实体id数组
	 */
	void deleteById(ID[] ids);

	/**
	 * 
	 * @return 返回总记录数
	 */
	int count();

	/**
	 * 
	 * @return 返回所有实体
	 */
	List<T> findAll();

	/**
	 * 
	 * @return Page<T> 返回所有实体组成的Page对象
	 */
	Page<T> findPage();

	/**
	 * 通过ID查找实体
	 * 
	 * @param id
	 *            要查找实体的ID
	 * @return 返回对应ID的实体，如果未找到则返回{@code null}
	 */
	T find(ID id);

	/**
	 * 根据属性值查找实体列表
	 * 
	 * @param name
	 *            属性名称
	 * @param value
	 *            属性对应的值
	 * @return 列表
	 */
	List<T> findByProperty(String name, Object value);

	/**
	 * 根据属性值查找唯一实体
	 * 
	 * @param name
	 *            属性名称
	 * @param value
	 *            属性对应的值
	 * @return 返回唯一实体，如果未找到返回{@code null}
	 * @throws NonUniqueResultException
	 *             如果有多个符合条件的
	 */
	T findUniqueByProperty(String name, Object value);

	/**
	 * 同findByProperty("name",value);
	 */
	List<T> findByName(Object value);

	/**
	 * 同findUniqueByProperty("name", value);
	 */
	T findUniqueByName(Object value);

	/**
	 * 获取查询器
	 * 
	 * @return
	 */
	Query<T, T> query();

	<RT> Query<T, RT> query(Class<T> resultClass);

	<RT> RT unique(Query<T, RT> query);

	<RT> List<RT> list(Query<T, RT> query);

	<RT> Page<RT> page(Query<T, RT> query);

	<RT> int count(Query<T, RT> query);

	/**
	 * 获取实体Class类型
	 * 
	 * @return 实体Class类型
	 * @throws RuntimeException
	 *             如果无法获取实体Class类型
	 */
	Class<T> getEntityClass();
}
